#include <nds.h>

#include <stdlib.h>
#include <stdio.h>
#include <time.h> 

s8 debugging;
#include "drawing.h"
#include "level.h"
#include "gameObject.h"
#include "character.h"
#include "player.h"
#include "dialogue.h"

//Global stuff
int frame;

static uint16* fb_front = VRAM_A;
static uint16* fb_back = VRAM_B;  //Always write to back framebuffer since it is hidden

void flip_vram()
{
	if (fb_front == VRAM_A) {
		fb_front = VRAM_B;
		fb_back = VRAM_A;
		videoSetMode(MODE_FB1);
	} else {
		fb_front = VRAM_A;
		fb_back = VRAM_B;
		videoSetMode(MODE_FB0);
	}
}

void checkEdges(player *P, level *L)
{
	// collision with boundaries
	if(P->_x > SCREEN_WIDTH - 15) //Right door
	{	
		P->_x = 2;
		L->_currentRoom = L->_currentRoom + 1;
		L->_rooms[L->_currentRoom]._discovered = true;
	}
		
	else if(P->_x < 1) 			//Left Door
	{	
		P->_x = SCREEN_WIDTH - 18;
		L->_currentRoom = L->_currentRoom - 1;
		L->_rooms[L->_currentRoom]._discovered = true;
	}
	
	else if(P->_y > SCREEN_HEIGHT - 15) //Bottom Door
	{
		P->_y = 2;
		L->_currentRoom = L->_currentRoom + 10;
		L->_rooms[L->_currentRoom]._discovered = true;
	}
	
	else if(P->_y < 2)				// Top Door
	{
		P->_y = SCREEN_HEIGHT - 18;
		L->_currentRoom = L->_currentRoom - 10;
		L->_rooms[L->_currentRoom]._discovered = true;
	}

}
bool checkPlayerMapCollision(u16 x, u16 y, room r)
{			
	// Collision with solid tiles
	for(u16 yy = 0; yy < MAX_TILE_Y; yy++)
	{
		for (u16 xx = 0; xx < MAX_TILE_X; xx++)
		{
			if(r._tiles[yy*MAX_TILE_X+xx] >= 5 && r._tiles[yy*MAX_TILE_X+xx] < 22)
			{
				if((x+15 > xx*16) && (x < (xx*16)+15) && (y+16 > (yy*16)) && (y < (yy*16)+8)) return true;		
			}
		}
	}
	// No collisions?  Let's return false
	return false;
}


//---------------------------------------//
//              MAIN FUNCTION            //
//---------------------------------------//
int main(void) {
	//We use the current system time as a seed for rand()
	//This isn't ideal but it's a good starting point.
	time_t unixTime = time(NULL);
	struct tm* timeStruct = gmtime((const time_t *)&unixTime);
	uint seed = timeStruct->tm_hour * timeStruct->tm_sec;
	
	
	//consoleDemoInit();

// Main engine setup
	vramSetBankA(VRAM_A_LCD);
	vramSetBankB(VRAM_B_LCD);
	
	videoSetMode(MODE_FB0);
	
// Sub engine setup
	vramSetBankC (VRAM_C_SUB_BG); 
	videoSetModeSub (MODE_5_2D | DISPLAY_BG3_ACTIVE); 
  
	REG_BG3CNT_SUB = BG_BMP16_256x256 | BG_BMP_BASE(0); 
	REG_BG3PA_SUB = 1 << 8; 
	REG_BG3PB_SUB = 0; 
	REG_BG3PC_SUB = 0; 
	REG_BG3PD_SUB = 1 << 8;

	lcdMainOnTop();  
  
	frame = seed;
	srand(frame);
	
	//Instansiate our rooms and characters
	level Level;
	
	player Player(120, 88);
	
	
	//Level.PopulateRooms();
	
	//dialogue Dia;
	
	//Clear Screens
	floodBg(fb_back, RGB15(0, 0, 0) | BIT(15)); // Set BG for top screen
	floodBg(BG_GFX_SUB, RGB15(0,0,0) | BIT(15)); // Set BG for bottom screen
	
	//Button mapping
	touchPosition touch;
	int pressed;
	int held;
		
	dialogue Dia;
	int charFrame = 0;
	//Debugging info
	//iprintf("\x1b[1;0HTile 0 = %d",Level._rooms[15]._tiles[0]);
	bool doDialogue = true;
	//Game Loop
	while(1) 
	{
// UPDATING 
		
	
// PROCESS INPUT
		scanKeys();
		
		touchRead(&touch);
		pressed = keysDown();
		held = keysHeld();
		
		if (pressed & KEY_START) break;	
		
		//Rebuild Maze TESTING
		if (pressed & KEY_A)
		{
			floodBg(BG_GFX_SUB, RGB15(0, 0, 0));
			Level.PopulateRooms();
		}
		
		if (pressed & KEY_B)
		{
			floodBg(BG_GFX_SUB, RGB15(0,0,0) | BIT(15)); // Set BG for bottom screen
			Level._map ^= 1;
			doDialogue ^= 1;
		}
		
		if (held & KEY_TOUCH)
		{
			BG_GFX_SUB[touch.py * SCREEN_WIDTH + touch.px] = RGB15(31, 31, 31) | BIT(15);
		}
		
		if (held & KEY_UP)
		{
			Player.Move(0, -2);				
		}
		if (held & KEY_DOWN)
		{
			Player.Move(0, 2);
		}
		if (held & KEY_LEFT)
		{
			Player.Move(-2, 0);
		}
		if (held & KEY_RIGHT)
		{
			Player.Move(+2, 0);	
		}
		
		if(checkPlayerMapCollision(Player._x, Player._y, Level._rooms[Level._currentRoom]))
		{
			Player._x = Player._oldx;
			Player._y = Player._oldy;
		}
		checkEdges(&Player, &Level);
		
		Player._oldx = Player._x;
		Player._oldy = Player._y;
//RENDERING
		
		Level.RenderMap(BG_GFX_SUB);	//Render Map on bottom screen	
		Level.RenderCurrentRoom(fb_back);	//Render Room on top screen
		Player.Render(fb_back, Player._x, Player._y, playerGFX_palette, playerGFX_sprites, 1);
		Player.RenderStats(BG_GFX_SUB);
		
		if(doDialogue) Dia.RenderDBox(fb_back);
		
		flip_vram();
		// erase back screen
		uint16 col = RGB15(0, 0, 0) | BIT(15);
		uint32 colcol = col | col << 16;
		
		swiFastCopy(&colcol, fb_back, 192*256*2/4 | COPY_MODE_FILL);
		
		swiWaitForVBlank();
	}
}
